<!-- <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/jquery.searchableSelect.js"></script> -->


<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/htmlUtils.js"></script>
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/KNXFunctionCodeSnippets.js"></script>

<script type="text/javascript">
    RED.nodes.registerType('knxUltimate', {
        category: "KNX Ultimate",
        color: '#7dd484',
        defaults: {
            //buttonState: {value: true},
            server: { type: "knxUltimate-config", required: true },
            topic: { value: "" },
            setTopicType: { value: "str" },
            outputtopic: { value: "" },
            dpt: { value: "" },
            initialread: { value: 0 },
            notifyreadrequest: { value: false },
            notifyresponse: { value: false },
            notifywrite: { value: true },
            notifyreadrequestalsorespondtobus: { value: false },
            notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized: { value: "0" },
            name: { value: "" },
            outputtype: { value: "write" },
            outputRBE: { value: "true" },
            inputRBE: { value: "false" },
            formatmultiplyvalue: { value: 1 },
            formatnegativevalue: { value: "leave" },
            formatdecimalsvalue: { value: 999 },
            passthrough: { value: "no" },
            sendMsgToKNXCode: { value: "" },
            receiveMsgFromKNXCode: { value: "" },
            listenallga: { value: "" }
        },
        inputs: 1,
        outputs: 1,
        icon: "node-knx-icon.svg",
        label: function () {
            const functionSendMsgToKNXCode = (this.sendMsgToKNXCode !== undefined && this.sendMsgToKNXCode !== '') ? "f(x) " : "";
            const functionreceiveMsgFromKNXCode = (this.receiveMsgFromKNXCode !== undefined && this.receiveMsgFromKNXCode !== '') ? " f(x)" : "";
            return ((this.outputRBE === "true" || this.outputRBE === true) ? "|rbe| " : "") + functionSendMsgToKNXCode + (this.name || this.topic || "KNX Device") + (this.setTopicType === 'str' || this.setTopicType === undefined ? '' : ' [' + (this.setTopicType === 'listenAllGA' ? 'Universal' : this.setTopicType) + ']') + functionreceiveMsgFromKNXCode + ((this.inputRBE === "true" || this.inputRBE === true) ? " |rbe|" : "")
        },
        paletteLabel: "KNX DEVICE",
        // button: {
        //     enabled: function() {
        //         // return whether or not the button is enabled, based on the current
        //         // configuration of the node
        //         return !this.changed
        //     },
        //     visible: function() {
        //         // return whether or not the button is visible, based on the current
        //         // configuration of the node
        //         return this.hasButton
        //     },
        //     //toggle: "buttonState",
        //     onclick: function() {}
        // },
        oneditprepare: function () {
            // Go to the help panel
            try {
                RED.sidebar.show("help");
            } catch (error) { }


            var node = this;
            if ($("#node-input-server").val() === "_ADD_") {
                // Node-Red 4.0.x has a bug not selecting the default server node
                try {
                    $("#node-input-server").prop("selectedIndex", 0);
                } catch (error) {
                }
            }
            var oNodeServer = RED.nodes.node($("#node-input-server").val()); // Store the config-node
            $("#tabs").tabs();

            // 15/09/2020 Supergiovane, set the help sample based on Datapoint
            function knxUltimateDptsGetHelp(_dpt, _forceClose) {
                if ($("#node-input-server").val() !== "_ADD_" && $("#node-input-server").val() !== '' && _dpt !== null && _dpt !== '') {
                    $.getJSON("knxUltimateDptsGetHelp?dpt=" + _dpt + "&serverId=" + $("#node-input-server").val() + "&" + { _: new Date().getTime() }, (data) => {
                        try {
                            $("#example-editor").html("");
                            $("#sampleCodeEditor").html();
                            node.sampleEditor.destroy();
                            delete node.sampleEditor;
                        } catch (error) {
                        }
                        try {
                            if (data.help !== "NO") {
                                node.sampleEditor = RED.editor.createEditor({
                                    id: 'example-editor',
                                    mode: 'ace/mode/javascript',
                                    value: data.help//this.exampleText
                                })//.renderer.setShowGutter(false);//A.setReadOnly(true).setShowPrintMargin(false);                    
                                if (data.helplink !== "") $("#sampleCodeEditor").html("&nbsp<i class=\"fa fa-question-circle\"></i>&nbsp<a target=\"_blank\" href=\"" + data.helplink + "\"><u>Link example of " + _dpt + "</u></a>");
                            } else {
                                // No help avaiable
                                node.sampleEditor = RED.editor.createEditor({
                                    id: 'example-editor',
                                    mode: 'ace/mode/javascript',
                                    value: "Currently, no sample payload is avaiable, sorry."
                                })//.renderer.setShowGutter(false);//B.setReadOnly(true).setShowPrintMargin(false);
                                if (data.helplink !== "") $("#sampleCodeEditor").html("&nbsp<i class=\"fa fa-question-circle\"></i>&nbsp<a target=\"_blank\" href=\"" + data.helplink + "\"><u>Link to wiki</u></a>");
                            }
                        } catch (error) {
                        }
                    })
                }
            }

            node.sendMsgToKNXCodeEditor = RED.editor.createEditor({
                id: 'sendMsgToKNXCode-editor',
                mode: 'ace/mode/nrjavascript',
                value: node.sendMsgToKNXCode
            });
            node.receiveMsgFromKNXCodeEditor = RED.editor.createEditor({
                id: 'receiveMsgFromKNXCode-editor',
                mode: 'ace/mode/nrjavascript',
                value: node.receiveMsgFromKNXCode
            });
            // Snippets
            $("#snippetOne").on("click", function (event) {
                node.sendMsgToKNXCodeEditor.session.setValue(KNXFunctionSnippetOne);
            });
            $("#snippetTwo").on("click", function (event) {
                node.receiveMsgFromKNXCodeEditor.session.setValue(KNXFunctionSnippetTwo);
            });
            $("#snippetThree").on("click", function (event) {
                node.receiveMsgFromKNXCodeEditor.session.setValue(KNXFunctionSnippetThree);
            });

            function checkUI() {

                // Backward compatibility
                if (node.outputRBE === true || $("#node-input-outputRBE").val() === true) {
                    node.outputRBE = 'true';
                    $("#node-input-outputRBE").val("true")
                }
                if (node.outputRBE === undefined || node.outputRBE === false || $("#node-input-outputRBE").val() === false) {
                    node.outputRBE = 'false';
                    $("#node-input-outputRBE").val("false")
                }
                if (node.inputRBE === true || $("#node-input-inputRBE").val() === true) {
                    node.inputRBE = 'true';
                    $("#node-input-inputRBE").val("true")
                }
                if (node.inputRBE === undefined || node.inputRBE === false || $("#node-input-inputRBE").val() === false) {
                    node.inputRBE = 'false';
                    $("#node-input-inputRBE").val("false")
                }
                if (node.passthrough === undefined) {
                    node.passthrough = 'no';
                    $("#node-input-passthrough").val("no")
                }
                if (node.initialread === undefined || node.initialread === false) {
                    node.initialread = 0;
                    $("#node-input-initialread").val(0)
                }

                oNodeServer = RED.nodes.node($("#node-input-server").val());
                if (oNodeServer === undefined) {
                    // Show the DEPLOY FIRST message
                    $("#divDeployFirst").show();
                    $("#divMain").hide();
                } else {
                    $("#divDeployFirst").hide();
                    $("#divMain").show();
                    try {
                        if (typeof oNodeServer.csv !== "undefined" && oNodeServer.csv !== "") {
                            $("#isETSFileLoaded").val("si");
                            $("#divknxFunctionHelperGAList").show();
                        } else {
                            $("#isETSFileLoaded").val("no");
                            $("#divknxFunctionHelperGAList").hide();
                        }
                    } catch (error) {
                        $("#isETSFileLoaded").val("no");
                        $("#divknxFunctionHelperGAList").hide();
                    }
                    if (oNodeServer.knxSecureSelected) {
                        $("#divknxsecure").show();
                    } else {
                        $("#divknxsecure").hide();
                    }

                    if ($("#node-input-server").val() !== "_ADD_" && $("#node-input-server").val() !== '') {
                        $.getJSON("knxUltimateDpts?serverId=" + $("#node-input-server").val() + "&_=" + new Date().getTime(), (data) => {
                            $("#node-input-dpt").empty();
                            data.forEach(dpt => {
                                $("#node-input-dpt").append($("<option></option>")
                                    .attr("value", dpt.value)
                                    .text(dpt.text))
                            });
                            $("#node-input-dpt").val(node.dpt);
                            // Load help sample
                            knxUltimateDptsGetHelp(node.dpt, true);
                        })
                    }

                    // Add write and response as default for existing nodes like was default before
                    if (node.notifywrite === undefined) {
                        node.notifywrite = true
                        node.notifyresponse = true
                        $("#node-input-notifywrite").prop("checked", true)
                        $("#node-input-notifyresponse").prop("checked", true)
                    }

                    // Add Write as default for existing clients output
                    if (node.outputtype === undefined) {
                        node.outputtype = "write"
                        $("#node-input-outputtype").val("write")
                    }

                    $("#node-input-notifyreadrequest").on('change', function () {
                        if ($("#node-input-notifyreadrequest").is(":checked")) {
                            if ($("#node-input-setTopicType").val() === "listenAllGA") {
                            } else {
                                $("#divnotifyreadrequestautoreact").show();
                            }
                        } else {
                            $("#divnotifyreadrequestautoreact").hide();
                        }
                    })

                    // Set the group address type
                    if (node.setTopicType === undefined) {
                        node.setTopicType = 'str';
                        $("#node-input-setTopicType").val('str');
                    }

                    // KNX Function helper: search for a GA and devicename
                    // ----------------------------------------------------------
                    try {
                        $("#node-input-knxFunctionHelperGAList").autocomplete('destroy');
                        $("#node-input-knxFunctionHelperGAList").removeClass(); // Rimuove eventuali classi aggiunte dall'autocompletamento  
                    } catch (error) { }
                    $("#node-input-knxFunctionHelperGAList").off(); // Rimuovi tutti gli eventi associati
                    $("#node-input-knxFunctionHelperGAList").val(''); // Pulisce il valore del campo di input, se necessario
                    $("#node-input-knxFunctionHelperGAList").autocomplete({
                        minLength: 0,
                        source: function (request, response) {
                            $.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id + "&" + { _: new Date().getTime() }, (data) => {
                                response($.map(data, function (value, key) {
                                    var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
                                    if (htmlUtilsfullCSVSearch(sSearch, request.term)) {
                                        return {
                                            label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
                                            value: value.ga + " " + value.devicename // Value
                                        }
                                    } else {
                                        return null;
                                    }
                                }));
                            });
                        }, select: function (event, ui) {
                        }
                    }).focus(function () {
                        $(this).autocomplete('search', $(this).val() + 'exactmatch');
                    });
                    // ----------------------------------------------------------


                    $("#node-input-setTopicType").on('change', function () {
                        try {
                            $("#divDatapointSelection").show();
                            $("#node-input-topic").show();
                            $("#node-input-topic").autocomplete('destroy');
                            $("#node-input-topic").off(); // Rimuovi tutti gli eventi associati
                            $("#node-input-topic").val(''); // Pulisce il valore del campo di input, se necessario
                            $("#node-input-topic").prop('disabled', false); // Assicura che il campo non sia disabilitato
                            $("#node-input-topic").removeClass(); // Rimuove eventuali classi aggiunte dall'autocompletamento                           
                        } catch (error) {
                        }
                        if ($("#node-input-setTopicType").val() === 'str') {
                            $("#node-input-topic").prop('placeholder', 'Select your GA');
                            // Autocomplete suggestion with ETS csv File
                            $("#node-input-topic").autocomplete({
                                minLength: 0,
                                source: function (request, response) {
                                    $.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id + "&" + { _: new Date().getTime() }, (data) => {
                                        response($.map(data, function (value, key) {
                                            var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
                                            if (htmlUtilsfullCSVSearch(sSearch, request.term)) {
                                                return {
                                                    label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
                                                    value: value.ga // Value
                                                }
                                            } else {
                                                return null;
                                            }
                                        }));
                                    });
                                }, select: function (event, ui) {
                                    // Sets Datapoint and device name automatically
                                    var sDevName = ui.item.label.split("#")[1].trim();
                                    try {
                                        sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
                                    } catch (error) {
                                    }
                                    $('#node-input-name').val(sDevName);
                                    var optVal = $("#node-input-dpt option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
                                    // Select the option value 
                                    $("#node-input-dpt").val(optVal);
                                    $("#node-input-dpt").trigger("change");
                                }
                            }).focus(function () {
                                $(this).autocomplete('search', $(this).val() + 'exactmatch');
                            });
                            $("#divDatapointSelection").show();
                            $("#divNode-input-initialread").show();
                            $("#divOutputRBE").show()
                            $("#divInputRBE").show()
                        } else if ($("#node-input-setTopicType").val() === 'listenAllGA') {
                            $("#node-input-topic").hide();
                            $("#divDatapointSelection").hide()
                            $("#divOutputRBE").hide()
                            $("#node-input-outputRBE").val("false")
                            $("#divInputRBE").hide()
                            $("#node-input-inputRBE").val("false")
                            $("#divnotifyreadrequestautoreact").hide();
                            $("#divTopic").hide()
                            $("#divNode-input-initialread").hide();

                            // Call a fake datapoint to load a sample "Universal Node"
                            knxUltimateDptsGetHelp("0.000", true); // 15/09/2020 Supergiovane, load sample help

                        } else {

                            // 15/09/2020 Supergiovane, load the help sample of the current datapoint
                            knxUltimateDptsGetHelp($("#node-input-dpt").val(), false); // 15/09/2020 Supergiovane, load sample help
                            $("#divOutputRBE").show()
                            $("#divInputRBE").show()
                            $("#divTopic").show()
                            if ($("#node-input-notifyreadrequest").is(":checked")) {
                                $("#divnotifyreadrequestautoreact").show();
                            } else {
                                $("#divnotifyreadrequestautoreact").hide();
                            }
                            $("#divNode-input-initialread").show();

                            $("#node-input-topic").prop('placeholder', $("#node-input-setTopicType").val());
                            if ($("#node-input-topic").val() === '') $("#node-input-topic").val('MyVariable');
                            $("#divDatapointSelection").hide();
                        }
                    });


                    // Hide or show the GA and DPT fields if Notify on all Group Addresses is checked
                    if (oNodeServer !== undefined && oNodeServer !== null) {
                        if (oNodeServer.csv !== undefined && oNodeServer.csv !== "") {
                            // There is a ETS csv file, show the init read option
                            $("#divNode-input-initialread").show()
                        } else {
                            // 25/10/2019 Warn user that the node will node encode/decode datagram, if Listen All GA's if the config node doesn't contain the csv
                            if ($("#node-input-setTopicType").val() === 'listenAllGA') {
                                // There isn't a ETS csv file, hide and deselect the init read option
                                $("#divNode-input-initialread").hide();
                                $("#node-input-initialread").val(0);
                            } else {
                                $("#divNode-input-initialread").show()
                            }
                        }
                    } else {
                        $("#node-input-setTopicType").val('str')
                        $("#divTopic").show()
                        $("#divDatapointSelection").show()
                        $("#divOutputRBE").show()
                        $("#divInputRBE").show()
                        $("#divNode-input-initialread").show()
                    }

                    // *****************************

                    setTimeout(() => {
                        if ($("#node-input-setTopicType").val() === 'listenAllGA') {
                            // Call a fake datapoint to load a sample "Universal Node"
                            knxUltimateDptsGetHelp("0.000", true); // 15/09/2020 Supergiovane, load sample help
                        }
                    }, 300);

                }
            }

            // 02/04/2020 Alert user about data type
            // ###########################
            $("#node-input-dpt").on("change", function (event) {
                // Load help sample
                knxUltimateDptsGetHelp(event.target.value, false);
            });
            // ###########################

            // If KNX Function is populated, set focus on the KNX Function tab.
            if (this.sendMsgToKNXCodeEditor.getValue() !== '' || this.receiveMsgFromKNXCodeEditor.getValue()) {
                $("#tabs").tabs(
                    { active: 1 }
                );
            }

            // Backwart compatibility listenAllGA
            if (node.listenallga === true) {
                $("#node-input-setTopicType").val('listenAllGA');
            }

            // 19/02/2020 Used to alert the user if the CSV file has not been loaded and to get the server sooner als deploy
            // ###########################
            $("#node-input-server").change(function () {
                checkUI();
            });
            // ###########################

        },
        oneditsave: function () {
            // Return to the info tab
            try {
                RED.sidebar.show("info");
            } catch (error) { }

            var node = this;
            this.sendMsgToKNXCode = this.sendMsgToKNXCodeEditor.getValue();
            this.receiveMsgFromKNXCode = this.receiveMsgFromKNXCodeEditor.getValue();
            if ($("#node-input-setTopicType").val() === "listenAllGA") {
                this.listenallga = true;
            } else {
                this.listenallga = false;
            }
            //this.propertyType = $("#node-input-property").typedInput('type');

            // 19/02/2020 Warn user that the node will node encode/decode datagram, if Listen All GA's if the config node doesn't contain the csv
            if ($("#isETSFileLoaded").val() === "no") {
                // Notify the user
                if ($("#node-input-setTopicType").val() === 'listenAllGA') {
                    var checkResult = node._("knxUltimate.advanced.notify-NoETSFile");
                    var myNotification = RED.notify(checkResult,
                        {
                            modal: true,
                            fixed: true,
                            type: 'error',
                            buttons: [
                                {
                                    text: "OK",
                                    click: function (e) {
                                        myNotification.close();
                                    }
                                }]
                        })
                }
                // $("#node-input-listenallga").prop("checked", false)
                // $("#divOutputRBE").show()
                // $("#divInputRBE").show()               
            }

            // 15/09/2020 Supergiovane, Detele the sample help editor
            try {
                node.sampleEditor.destroy();
                delete node.sampleEditor;
                node.sendMsgToKNXCodeEditor.destroy();
                delete node.sendMsgToKNXCodeEditor;
                node.receiveMsgFromKNXCodeEditor.destroy();
                delete node.receiveMsgFromKNXCodeEditor;
                //RED.editor.destroy(); // 23/01/2024 added  
            } catch (error) { }

        },
        oneditcancel: function () {
            // Return to the info tab
            try {
                RED.sidebar.show("info");
            } catch (error) { }

            // 15/09/2020 Supergiovane, Detele the sample help editor
            try {
                node.sampleEditor.destroy();
                delete node.sampleEditor;
                node.sendMsgToKNXCodeEditor.destroy();
                delete node.sendMsgToKNXCodeEditor;
                node.receiveMsgFromKNXCodeEditor.destroy();
                delete node.receiveMsgFromKNXCodeEditor;
                RED.editor.destroy(); // 23/01/2024 added  
            } catch (error) { }
        }
    })

    // RED.events.on("nodes:change", function (node) {

    //     checkUI();

    // });

</script>

<script type="text/html" data-template-name="knxUltimate">

    <!-- Setted by oneditprepare and used in oneditsave to warn user if no CSV file has been loaded -->
<input id="isETSFileLoaded" name="isETSFileLoaded" type="hidden" value="false" />

<div class="form-row">
    <b>KNX Device node</b>
    <br />
    <br />

    <label for="node-input-server">
        <i class="fa fa-circle-o"></i> Gateway
    </label>
    <input type="text" id="node-input-server" />
</div>

<div id="divMain">

    <div class="form-row">
        <label for="node-input-topic">
            <img
                src=""></img>
            Group Addr.</label>
        <select id="node-input-setTopicType" style="width:120px">
            <option value="str">3-Levels</option>
            <option value="listenAllGA">Universal mode (listen to all Group Addresses)</option>
            <option value="flow">Flow</option>
            <option value="global">Gobal</option>
            <option value="env">$Env variable</option>
        </select>
        <input type="text" id="node-input-topic" placeholder="Start typing to search" style="width:180px" />
    </div>


    <div class="form-row" id="divDatapointSelection">
        <label for="node-input-dpt">
            <img
                src=""></img>
            Datapoint
        </label>
        <select id="node-input-dpt"></select>
        <span id="sampleCodeEditor" style="color:red;" />
    </div>
    <!-- <div class="form-row">
        <input type="checkbox" id="node-input-listenallga"
            style="display:inline-block; width:auto; vertical-align:top;" />
        <label style="width:auto" for="node-input-listenallga">
            <img
                src=""></img>
            <span data-i18n="knxUltimate.properties.node-input-listenallga"></span>
        </label>
    </div> -->
    <div id="tabs">
        <ul>
            <li><a href="#tabs-1"><i class="fa fa-braille"></i> Advanced options</a></li>
            <li><a href="#tabs-2"><i class="fa fa-code"></i> KNX Function</a></li>
            <li><a href="#tabs-3"><i class="fa fa-medkit"></i> Payload Sample</a></li>
        </ul>
        <div id="tabs-1">
            <div class="form-row" style="padding:10px">
                <div class="form-row">
                    <dt>
                        <i class="fa fa-desktop"></i> General properties
                    </dt>
                </div>
                <div class="form-row">
                    <label style="width:180px" for="node-input-name">
                        <i class="fa fa-tag"></i>
                        <span data-i18n="knxUltimate.properties.node-input-name"></span>
                    </label>
                    <input style="width:220px;" type="text" id="node-input-name"
                        data-i18n="[placeholder]knxUltimate.properties.node-input-name" />
                </div>
                <div class="form-row" id="divTopic">
                    <label style="width:180px" for="node-input-outputtopic">
                        <i class="fa fa-tasks"></i>
                        <span data-i18n="knxUltimate.properties.node-input-outputtopic"></span>
                    </label>
                    <input style="width:220px;" type="text" id="node-input-outputtopic"
                        data-i18n="[placeholder]knxUltimate.placeholder.leaveempty" />
                </div>
                <div class="form-row">
                    <label style="width:180px" for="node-input-passthrough">
                        <i class="fa fa-long-arrow-right"></i> Passthrough
                    </label>
                    <select id="node-input-passthrough">
                        <option value="no">No</option>
                        <option value="yes">Yes, pass the input msg to the output msg</option>
                        <option value="yesownprop">Yes, but put the input msg into msg.inputmessage property of the
                            output msg
                        </option>
                    </select>
                </div>
                <hr>
                <div class="form-row">
                    <dt>
                        <i class="fa fa-arrow-right"></i>| From node's INPUT PIN to KNX BUS
                    </dt>
                </div>
                <div class="form-row">
                    <label style="width:180px" for="node-input-outputtype">
                        <i class="fa fa-paper-plane-o"></i> Telegram type
                    </label>
                    <select id="node-input-outputtype">
                        <option value="write" data-i18n="knxUltimate.selectlists.Output_write"></option>
                        <option value="response" data-i18n="knxUltimate.selectlists.Output_response"></option>
                        <option value="read" data-i18n="knxUltimate.selectlists.Output_read"></option>
                        <option value="update" data-i18n="knxUltimate.selectlists.Output_update"></option>
                    </select>
                </div>
                <div class="form-row" id="divOutputRBE">
                    <label style="width:180px" for="node-input-outputRBE">
                        <i class="fa fa-filter"></i> RBE filter
                    </label>
                    <select id="node-input-outputRBE">
                        <option value="true">Enable (send the payload to KNX only if changed)</option>
                        <option value="false">Disable</option>
                    </select>
                </div>
                <hr>
                <div class="form-row">
                    <dt>
                        |<i class="fa fa-arrow-right"></i> From KNX BUS to node's ouput PIN
                    </dt>
                </div>
                <div class="form-row" id="divNode-input-initialread">
                    <label style="width:180px" for="node-input-initialread">
                        <i class="fa fa-question-circle-o"></i> Read status on start
                    </label>
                    <select id="node-input-initialread">
                        <option value=0 data-i18n="knxUltimate.properties.node-input-initialread0"></option>
                        <option value=1 data-i18n="knxUltimate.properties.node-input-initialread1"></option>
                        <option value=2 data-i18n="knxUltimate.properties.node-input-initialread2"></option>
                        <option value=3 data-i18n="knxUltimate.properties.node-input-initialread3"></option>
                    </select>

                </div>
                <div class="form-row" id="divInputRBE">
                    <label style="width:180px" for="node-input-inputRBE">
                        <i class="fa fa-filter"></i> RBE filter
                    </label>
                    <select id="node-input-inputRBE">
                        <option value="true">Enable (react only if payload changes)</option>
                        <option value="false">Disable</option>
                    </select>
                </div>
                <div class="form-row">
                    <input type="checkbox" id="node-input-notifywrite"
                        style="display:inline-block; width:auto; vertical-align:top;" />
                    <label style="width:85%" for="node-input-notifywrite">
                        <i class="fa fa-sign-in"></i> React to write telegrams
                    </label>
                </div>
                <div class="form-row">
                    <input type="checkbox" id="node-input-notifyresponse"
                        style="display:inline-block; width:auto; vertical-align:top;" />
                    <label style="width:85%" for="node-input-notifyresponse">
                        <i class="fa fa-sign-in"></i> React to response telegrams
                    </label>
                </div>
                <div class="form-row">
                    <input type="checkbox" id="node-input-notifyreadrequest"
                        style="display:inline-block; width:auto; vertical-align:top;" />
                    <label style="width:85%" for="node-input-notifyreadrequest">
                        <i class="fa fa-sign-in"></i> React to read telegrams
                    </label>
                </div>
                <div id="divnotifyreadrequestautoreact">
                    <dd>
                        <div class="form-row">
                            <input type="checkbox" id="node-input-notifyreadrequestalsorespondtobus"
                                style="display:inline-block; width:auto; vertical-align:top;" />
                            <label style="width:85%" for="node-input-notifyreadrequestalsorespondtobus">
                                <span
                                    data-i18n="knxUltimate.properties.node-input-notifyreadrequestalsorespondtobus"></span>
                            </label>
                        </div>
                        <div class="form-row">
                            &nbsp;<label style="width:auto">
                                <span
                                    data-i18n="knxUltimate.properties.node-input-notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized"></span>
                            </label>
                            <input style="width:auto" type="text"
                                id="node-input-notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized"
                                data-i18n="[placeholder]knxUltimate.placeholder.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized" />
                        </div>
                    </dd>
                </div>
                <div class="form-row">
                    <dt>
                        <i class="fa fa-sort-numeric-asc"></i> Format numeric values coming from the KNX BUS
                    </dt>
                </div>
                <div class="form-row">
                    <label style="width:180px" for="node-input-formatmultiplyvalue">
                        <i class="fa fa-calculator"></i>
                        <span data-i18n="knxUltimate.properties.node-input-formatmultiplyvalue"></span>
                    </label>
                    <select id="node-input-formatmultiplyvalue">
                        <option value=1 data-i18n="knxUltimate.selectlists.Multiply_leave"></option>
                        <option value=0.001 data-i18n="knxUltimate.selectlists.Multiply_divide1000"></option>
                        <option value=0.01 data-i18n="knxUltimate.selectlists.Multiply_divide100"></option>
                        <option value=0.1 data-i18n="knxUltimate.selectlists.Multiply_divide10"></option>
                        <option value=10 data-i18n="knxUltimate.selectlists.Multiply_multiply10"></option>
                        <option value=100 data-i18n="knxUltimate.selectlists.Multiply_multiply100"></option>
                        <option value=1000 data-i18n="knxUltimate.selectlists.Multiply_multiply1000"></option>
                    </select>
                </div>
                <div class="form-row">
                    <label style="width:180px" for="node-input-formatdecimalsvalue">
                        <i class="fa fa-expand"></i>
                        <span data-i18n="knxUltimate.properties.node-input-formatdecimalsvalue"></span>
                    </label>
                    <select id="node-input-formatdecimalsvalue">
                        <option value=999 data-i18n="knxUltimate.selectlists.Decimals_leave"></option>
                        <option value=0 data-i18n="knxUltimate.selectlists.Decimals_roundint"></option>
                        <option value=1 data-i18n="knxUltimate.selectlists.Decimals_round1"></option>
                        <option value=2 data-i18n="knxUltimate.selectlists.Decimals_round2"></option>
                        <option value=3 data-i18n="knxUltimate.selectlists.Decimals_round3"></option>
                        <option value=4 data-i18n="knxUltimate.selectlists.Decimals_round4"></option>
                    </select>
                </div>
                <div class="form-row">
                    <label style="width:180px" for="node-input-formatnegativevalue">
                        <i class="fa fa-minus-circle"></i>
                        <span data-i18n="knxUltimate.properties.node-input-formatnegativevalue"></span>
                    </label>
                    <select id="node-input-formatnegativevalue">
                        <option value="leave" data-i18n="knxUltimate.selectlists.Negatives_leave"></option>
                        <option value="zero" data-i18n="knxUltimate.selectlists.Negatives_zero"></option>
                        <option value="abs" data-i18n="knxUltimate.selectlists.Negatives_abs"></option>
                    </select>
                </div>
            </div>
        </div>

        <div id="tabs-2">
            <div class="form-row" style="padding:10px">

                <div class="form-row" id="divknxFunctionHelperGAList">
                    <label for="node-input-knxFunctionHelperGAList">
                        <i class="fa fa-search"></i> Search GA
                    </label>
                    <input type="text" id="node-input-knxFunctionHelperGAList" placeholder="Start typing to search" />
                </div>


                <div class="form-row">
                    <dt>
                        <i class="fa fa-arrow-right"></i>| From node's INPUT PIN to KNX BUS
                    </dt>
                </div>
                <div style="height:200px;min-height:150px;padding:0px;">
                    <div style="height:100%;width:100%;padding:0px;" class="node-text-editor"
                        id="sendMsgToKNXCode-editor"></div>
                </div>
                <i class="fa fa-code"></i> Select a snippet to be inserted<br />
                <button type="button" id="snippetOne" class="red-ui-button">Status GA check</button>
                <hr>
                <div class="form-row">
                    <dt>
                        |<i class="fa fa-arrow-right"></i> From KNX BUS to node's OUTPUT PIN
                    </dt>
                </div>
                <div style="height:200px;min-height:150px;padding:0px;">
                    <div style="height:100%;width:100%;padding:0px;" class="node-text-editor"
                        id="receiveMsgFromKNXCode-editor"></div>
                </div>
                <i class="fa fa-code"></i> Select a snippet to be inserted<br />
                <button type="button" id="snippetTwo" class="red-ui-button">Show msg constructor</button>
                <button type="button" id="snippetThree" class="red-ui-button">Add property to msg</button>

            </div>
        </div>

        <div id="tabs-3">
            <div style="height:200px;min-height:150px;padding:0px;">
                <div style="height:100%;width:100%;padding:0px;" class="node-text-editor" id="example-editor"></div>
            </div>
        </div>
    </div>
</div>

<div id="divDeployFirst">
    <div class="form-tips" style="margin-top:11px">
        <span data-i18n="knxUltimate.deployfirst"></span>
    </div>
</div>
<br /><br />
</script>
<script type="text/markdown" data-help-name="knxUltimate">
<p>This node lets you control a KNX Group Address, this is the most used node.</p>  
    
[<i class="fa fa-code"></i> Here you'll find some samples](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/-SamplesHome)

**Configuration**
|Property|Description|
|--|--|
| Gateway | Select the KNX gateway to be used |
| GA Type dropdown list | The group address type. **3-Levels** is the default, where you can type the *3 level group address* or the *group address name* (if you've upload the ETS file), or **Global**, for reading the GA at startup from a global variable, or **Flow** that do the same as the *Global*, but at flow level. Select **$Env variable** to read the group address from an environment variable. Select **Universal mode (listen to all Group Addresses)** to react to ALL group addresses.|
| Group Addr. | The KNX Group Address you want to control. If you've imported the ETS group addresses file, you can just start typing in your device name. You can leave it empty if you wish set it with *msg.setConfig* input message. |
| Datapoint | The datapoint belonging to your node.|

<br/>
<br/>

## TAB Advanced options

|Property|Description|
|--|--|
||**General properties**|
| Node name | Self explaining. |
| Topic | The msg output topic. Leave it blank to have it set to your Group Address. |
| Passthrough | If set, you can pass the input mgs to the output msg. |
||**From node's INPUT PIN to KNX BUS**|
| Telegram type | *write* to send write telegram (usually, you want that), otherwise you can choose the telegram's type to react to. |
| RBE filter | *Report by change* filter. If set, only the msg input (from the Flow) having different values each time, will be sent to the KNX bus. If you intend to send everytime the same value, turn it off. If enabled, "rbe" indication will be added to node's name.|
||**From KNX BUS to node's ouput PIN**|
| Read status on start | Read group address status, every time Node-Red starts and at every reconnection to the KNX Gateway. The node stores all group address values to a file, so you can choose wether to read from file or from the KNX bus. |
| RBE filter | *Report by change* filter. If set, only the msg output (to KNX bus) having different values each time, will be sent to the msg output's flow. If you intend to send everytime the same value, leave it off.  If enabled, "rbe" indication will be added to node's name. |
| React to write telegrams | The node will react (will send a msg to the flow) each time it receives a *write* telegram from the KNX bus. Usually, you want that. |
| React to response telegrams | The node will react (will send a msg to the flow) each time it receives a *response* telegram from the KNX bus. Usually, you want that for particular scenarios. |
| React to read telegrams | The node will react (will send a msg to the flow) each time it receives a *read* telegram from the KNX bus. Usually, you want that if you're want to send a custom value to the KNX BUS. |
| Multiply | Multiplies or divides the payload value. Works only if the value is a number. |
| Decimals | Round or handle decimals in any way. Works only if the value is a number. |
| Negatives | Handles the negative values. Works only if the value is a number. |

<br/>
<br/>

## TAB KNX Function

You can use Javascript to modify the behaviour of the input msg coming from the flow and the output telegram sent to the KNX bus.  
The embedded code editor provides useful objects and functions to retrieve the value of all group addresses, both with the imported ETS file and without (specifying the datapoint).  
The script is called everytime the node receives a msg from the flow or a telegram from the KNX BUS.  
If enabled, "f(x)" indication will be added to node's name.

|Property|Description|
|--|--|
| Search GA | It's a helper only avaiable if the ETS file has been imported. Start typing and select the group address you wish to add to the code. Then copy the full field and paste it into the getGAValue function. <br/> **getGAValue('0/0/1 table nord lamp')** |

<br/>

### List of common object and functions you can use in the code

|Object or Function|Description|
|--|--|
| msg (object) | The current msg object received by the node. | 
| getGAValue (string GA, optional string DPT) | Get the specified GA's value, for example **'1/0/1'**, or also **'1/0/1 Bed table light'** (All text after a blank space will be ignored by the function. This is useful if you want to add the GA name as a reminder. With the ETS file imported, you can also copy and paste the GA and GA Name directly from the **Search GA** field.). **DPT** is optional if you've imported the ETS file, otherwise you must specify it, for example '1.001'. |
| setGAValue (string GA, any value, optional string DPT) | Set the specified GA's value. The GA con be wrote for example **'1/0/1'**, or also **'1/0/1 Bed table light'** (All text after a blank space will be ignored by the function. This is useful if you want to add the GA name as a reminder. With the ETS file imported, you can also copy and paste the GA and GA Name directly from the **Search GA** field.). The **value** is mandatory, can be a boolean or number or string, **DPT** is optional if you've imported the ETS file, otherwise you must specify it, for example '1.001'. |
| self (any value) | Set the currend node's value and sends the value to the KNX BUS as well. For example, *self(false)*. Caution using **self** function in the *From KNX BUS to node's OUTPUT PIN* code, because the code will be executed everytime a KNX telegram is received, so you coud have recurrency loops. |
| toggle (nothing) | Toggle the currend node's value and sends the value to the KNX BUS as well. For example, *toggle()*. Caution using **toggle** function in the *From KNX BUS to node's OUTPUT PIN* code, because the code will be executed everytime a KNX telegram is received, so you coud have recurrency loops. |
| node (object) | The node object. |
| RED (Node-Red object) | The Node-Red's RED object. |
| return (msg) | Mandatory `return msg;`, if you want to emit the message. Otherwise, using `return;` will not emit any message. |

### From KNX BUS to node's OUTPUT PIN

In this sample, we'll send the input msg to the KNX BUS only if another GA has opposite value.  
We'll turn on the light only if it's status GA is off, and vice versa. 
```javascript
const statusGA = getGAValue('0/0/09','1.001');
if (msg.payload !== statusGA){ // "!==" means "not equal"
    return msg;
}else{
    // Both values are identical, so i don't send the msg.
    return;
}
```

Here, if someone switches on the light, we turn on another light 0/1/8 and after 2 seconds we switch off the lamp connected to the node.  
```javascript
if (msg.payload){ 
    setGAValue('0/1/8',true)
    setTimeout(function() {
        self(off);
    }, 2000);
}
return msg;
```

### From KNX BUS to node's ouput PIN

In this sample, we'll emit the msg object to the flow, by appending the value of another GA to the output msg.  
The ouput msg to the flow will have also the external temp in the property `msg.externalTemperature`  
```javascript
// The current msg contains the internal temperature in the "msg.payload" property, but we want to emit the external temperature as well.
msg.externalTemperature = getGAValue('0/0/10'); // In case the ETS file is missing, you must specify the dpt as well: getGAValue('0/0/10','9.001')
return msg;
```

In this other sample, we'll not emit a msg to the flow, in case msg.payload and another GA value are both false.  
```javascript
if (msg.payload === false && getGAValue('0/0/11','1.001') === false){
    // Both false, don't emit the msg to the flow.
    return;
}else{
    // Ok, emit it.
    return msg;
}
```

<br/>
<br/>

## TAB Payload sample

|Property|Description|
|--|--|
| Sample | This will give it a hint on what to write in an external function node, if you want to control the node via a Node-Red function node. |

<br/>
<br/>
<br/>

### Inputs

: destination (string) : the destination group address, for example 1/1/0. Only 3-level is allowed.  
: payload (any) : the payload to be sent. Can be for example true or false, or an object.
: event (string) : can be *GroupValue_Write* to write the telegram to the KNX BUS, *GroupValue_Response* to send a response telegram to the KNX BUS, *Update_NoWrite*. *Update_NoWrite* sends nothings to the KNX BUS, just updates the internal value of the KNX-Ultimate node. This is useful if you wanna only store the value into the node and read it later with a read request.
: readstatus (boolean) : issue a read request to the KNX bus. Pass *true* everytime (msg.readstatus = true).
: dpt (string) : For example "1.001". Sets the Datapoint.
: writeraw (buffer): is used to send a value to the KNX bus, as buffer. Use in conjunction with *bitlenght*.
: bitlenght (int): specifies the lenght of the *writeraw* buffer. Use in conjunction with *writeraw*.
: resetRBE (boolean) : resets the internal RBE filters (*use msg.resetRBE = true*).
: setConfig (json) : programmatically change the KNX-Ultimate Device node Group Address and Datapoint. See details.

### Details

`msg.setConfig`: It's possible to programmatically change the KNX-Ultimate node configuration, by sending msg.setConfig object to the node.
The new configuration will be retained until next msg.setConfig or until restart/redeploy.
All properties (*setGroupAddress* and *setDPT*) **are mandatory**..  
Use it like that, in a functon node:    

**Set both GA and DPT**

```javascript
// Change the node properties as follows:
// setGroupAddress: set the new group address.
// setDPT: set the new Datapoint, as you can see in the dropdown list (the numeric part, for example "1.001", "237.600", etc...). If set to **auto**, the datapoint will be read from the ETS file (if present).
var config= {
    setGroupAddress: "0/1/2",
    setDPT: "1.001"
};
msg.setConfig = config;
return msg;
```

**Set GA and read the datapoint from the ETS file** 

```javascript
// Change the node properties as follows:
// setGroupAddress: set the new group address.
// setDPT: set the new Datapoint, as you can see in the dropdown list (the numeric part, for example "1.001", "237.600", etc...). If set to "auto", the datapoint will be read from the ETS file (if present).
var config= {
    setGroupAddress: "0/1/2",
    setDPT: "auto"
};
msg.setConfig = config;
return msg;
```

### Outputs

1. Standard output
: payload (string|number|object) : Pin 1 is the standard output of the command.

2. Errors
: error (object) : Pin 2 Contains the detailed error message. 

### Details

`msg.payload` is used as the payload of the group address (the group address value).
This is, instead, an example of the complete msg object.  

```json
msg = {
    topic: "0/1/2" // (Contains the node's topic, for example "MyTopic". If the node's topic is not set, contains the Group Address, for example "0/1/2")
    payload: false 
    previouspayload: true // Previous node payload value.
    payloadmeasureunit: "%" // Payload's measure unit.
    payloadsubtypevalue: "Start" // Subtype's decoded value, for exampe, On/Off, Ramp/NoRamp, Start/Stop, Alarm/NoAlarm
    devicename: "Dinning table lamp" // If the node is in **universal mode**, it contains the full path (main, middle,name) of the group address name, otherwise, the node name.
    gainfo: { // Contains the details about the group address name and number. This object is only present if the node is set in **universal mode** and with the **ETS file** been imported. If something wrong, it contains the string **unknown**.
        maingroupname:"Light actuators"
        middlegroupname:"First flow lights"
        ganame:"Table Light"
        maingroupnumber:"1"
        middlegroupnumber:"1"
        ganumber:"0"
    },
    echoed:true, // True if the msg is coming from the input PIN, otherwise false if the msg is coming form the KNX BUS.
    knx: { // This is a representation of the KNX BUS telegram, coming from BUS
        event: "GroupValue_Write" // (or "GroupValue_Response", or "GroupValue_Read")
        dpt: "1.001"
        dptdesc: "Humidity" // Payload's measure unit description
        source: "15.15.22"
        destination: "0/1/2" // Contains the Group Address
        rawValue: buffer[1]raw // (or null, if "GroupValue_Read")
            0: 0x0 // (This is the RAW undecoded value)
    }
}
````

<br/>

[![Donate via PayPal](https://raw.githubusercontent.com/Supergiovane/node-red-contrib-knx-ultimate/master/img/CodiceQR.png)](https://www.paypal.com/donate/?hosted_button_id=S8SKPUBSPK758)



</script>